package com.kedacom.ctsp.authz.oauth2;


import com.kedacom.ctsp.authz.oauth2.service.*;
import com.kedacom.ctsp.authz.oauth2.service.client.ClientCredentialGranter;
import com.kedacom.ctsp.authz.oauth2.service.client.DefaultClientCredentialGranter;
import com.kedacom.ctsp.authz.oauth2.service.code.AuthorizationCodeGranter;
import com.kedacom.ctsp.authz.oauth2.service.code.AuthorizationCodeService;
import com.kedacom.ctsp.authz.oauth2.service.code.DefaultAuthorizationCodeGranter;
import com.kedacom.ctsp.authz.oauth2.service.implicit.DefaultImplicitGranter;
import com.kedacom.ctsp.authz.oauth2.service.implicit.ImplicitGranter;
import com.kedacom.ctsp.authz.oauth2.service.password.DefaultPasswordGranter;
import com.kedacom.ctsp.authz.oauth2.service.password.PasswordGranter;
import com.kedacom.ctsp.authz.oauth2.service.password.PasswordService;
import com.kedacom.ctsp.authz.oauth2.service.refresh.DefaultRefreshTokenGranter;
import com.kedacom.ctsp.authz.oauth2.service.refresh.RefreshTokenGranter;
import com.kedacom.ctsp.lang.id.IDGenerator;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * TODO 完成注释
 *
 * @author zhouhao
 */
@Configuration
@EnableConfigurationProperties()
public class OAuth2ServerAutoConfiguration {

    @ConditionalOnMissingBean
    @Bean
    public TokenGenerator tokenGenerator() {
        return IDGenerator.UUID::generate;
    }

    @Bean
    public OAuth2ServerErrorControllerAdvice oAuth2ServerErrorControllerAdvice() {
        return new OAuth2ServerErrorControllerAdvice();
    }

    @ConditionalOnMissingBean
    @Bean
    public CodeGenerator codeGenerator() {
        return IDGenerator.UUID::generate;
    }

    @ConditionalOnMissingBean(AuthorizationCodeService.class)
    @Bean
    public AuthorizationCodeServiceImpl simpleAuthorizationCodeService() {
        return new AuthorizationCodeServiceImpl();
    }

    @ConditionalOnMissingBean(ClientService.class)
    @Bean
    public ClientService simpleClientService() {
        return new ClientServiceImpl();
    }

    @ConditionalOnMissingBean(PasswordService.class)
    @Bean
    public PasswordService simplePasswordService() {
        return new PasswordServiceImpl();
    }

    @ConditionalOnMissingBean(AccessTokenService.class)
    @Bean
    public AccessTokenService simpleAccessTokenService() {
        return new AccessTokenServiceImpl();
    }

    @Bean
    public AutoSettingOAuth2GranterImpl autoSettingOAuth2Granter() {
        return new AutoSettingOAuth2GranterImpl();
    }

    @Configuration
    public static class OAuth2GranterConfiguration {

        @Bean
        @ConditionalOnMissingBean(AuthorizationCodeGranter.class)
        public AuthorizationCodeGranter authorizationCodeGranter() {
            return new DefaultAuthorizationCodeGranter();
        }

        @Bean
        @ConditionalOnMissingBean(ClientCredentialGranter.class)
        public ClientCredentialGranter clientCredentialGranter() {
            return new DefaultClientCredentialGranter();
        }

        @Bean
        @ConditionalOnMissingBean(PasswordGranter.class)
        public PasswordGranter passwordGranter() {
            return new DefaultPasswordGranter();
        }

        @Bean
        @ConditionalOnMissingBean(ImplicitGranter.class)
        public ImplicitGranter implicitGranter() {
            return new DefaultImplicitGranter();
        }

        @Bean
        @ConditionalOnMissingBean(RefreshTokenGranter.class)
        public RefreshTokenGranter refreshTokenGranter() {
            return new DefaultRefreshTokenGranter();
        }

    }

    class AutoSettingOAuth2GranterImpl extends DefaultOAuth2GrantServiceImpl implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof AuthorizationCodeGranter) {
                addAuthorizationCodeSupport(((AuthorizationCodeGranter) bean));
            }
            if (bean instanceof ClientCredentialGranter) {
                addClientCredentialSupport(((ClientCredentialGranter) bean));
            }
            if (bean instanceof PasswordGranter) {
                addPasswordSupport(((PasswordGranter) bean));
            }
            if (bean instanceof ImplicitGranter) {
                addImplicitSupport(((ImplicitGranter) bean));
            }
            if (bean instanceof RefreshTokenGranter) {
                addRefreshTokenSupport((RefreshTokenGranter) bean);
            }
            return bean;
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    }

}
